#ifndef _SOCKET_H_
#define _SOCKET_H_

#include <stdint.h>
#include "ipaddr.h"
#include "net_err.h"
#include "sock.h"

#define SOCK_MAX_NR ((RAW_MAX_NR) + (DGRAM_MAX_NR))

#define IPV4_ADDR_STR_SIZE 16
#undef INADDR_ANY
#define INADDR_ANY (uint32_t)0x00000000

#undef AF_INET
#define AF_INET 2

#undef SOCK_RAW
#define SOCK_RAW 0
#undef SOCK_DGRAM
#define SOCK_DGRAM 1

#undef IPPROTO_ICMP
#define IPPROTO_ICMP 0x0001
#undef IPPROTO_UDP
#define IPPROTO_UDP 0x0011

#undef SOL_SOCKET
#undef SO_RCVTIMEO
#undef SO_SNDTIMEO
#undef timeval

#define SOL_SOCKET 0
#define SO_RCVTIMEO 1
#define SO_SNDTIMEO 2
#define timeval x_timeval

#pragma pack(1)

struct x_in_addr
{
    union
    {
        struct
        {
            uint8_t addr_0;
            uint8_t addr_1;
            uint8_t addr_2;
            uint8_t addr_3;
        };
        uint8_t add_array[IPV4_ADDR_SIZE];
#undef s_addr
        uint32_t s_addr;
    };
};

struct x_sockaddr
{
    uint8_t sin_len;
    uint8_t sin_family;
    uint8_t sa_data[14];
};

struct x_sockaddr_in
{
    uint8_t sin_len;
    uint8_t sin_family;
    uint16_t sin_port;
    struct x_in_addr sin_addr;
    char sin_zero[8];
};

#pragma pack()

typedef struct _x_socket_t
{
    enum
    {
        SOCKET_STATE_FREE,
        SOCKET_STATE_USED
    } state;

    sock_t *sock;
} x_socket_t;

struct x_timeval
{
    int tv_sec;
    int tv_usec;
};

int x_socket(int family, int type, int protocol);
int x_setsocketopt(int s, int level, int optname, const char *optval, int len);
ssize_t x_sendto(int s, const void *buf, size_t len, int flags, const struct x_sockaddr *dest, x_socklen_t dest_len);
ssize_t x_send(int s, const void *buf, size_t len, int flags);
ssize_t x_recvfrom(int s, char *buf, int len, int flags, struct x_sockaddr *from, int *fromlen);
ssize_t x_recv(int s, char *buf, int len, int flags);
int x_connect(int s, const struct x_sockaddr *addr, x_socklen_t len);
int x_bind(int s, const struct x_sockaddr *addr, x_socklen_t len);
int x_close(int s);

#endif